﻿using System;
using PSE.Deployment.Engine;
using PSE.Deployment.Engine.CustomExceptions;
using PSE.Deployment.Engine.Interfaces;
using PSE.Deployment.SetupBase;
using Sinacor.Deployment.Setup.DataAccess;
using Sinacor.Deployment.Setup.Main;
using Sinacor.Deployment.Setup.Parameter;
using PSE.Deployment.Util;

namespace Sinacor.Deployment.Setup.Install.DataBase.Steps
{
    public class CompanyInsert : BaseStep
    {
        private Company Company { get; set; }
        private int ExecutedCommandCount { get; set; }
        private Configuration.Script CompanyCommands { get; set; }

        public CompanyInsert(IStepGroup parent, Company company)
            : base(parent)
        {
            this.Company = company;

            this.Id = "DataBase.CompanyInsert." + this.Company.Id.ToString();
            this.Description = string.Format(StepDescriptions.COMPANY_INSERT, company.Name);

            this.ErrorBehavior = PSE.Deployment.Engine.Enums.StepErrorBehavior.NotifyParent;
            this.NavigationBehavior = PSE.Deployment.Engine.Enums.StepNavigationBehavior.NextCancel;

            ExecutedCommandCount = 0;

            CompanyCommands = SetupMainFactory.GetInstance<SinacorMain>().Configuration.Scripts.Scripts.Find(x => x.Schema == Sinacor.Deployment.Setup.Configuration.Enums.SchemaType.Company && x.Type == Sinacor.Deployment.Setup.Configuration.Enums.ScriptType.Insert);
            this.ResetProgress(CompanyCommands.Commands.Count);
        }

        public override void Execute()
        {
            ExecutedCommandCount = 0;

            this.ResetProgress(CompanyCommands.Commands.Count);

            using (OracleDataBase db = new OracleDataBase(SetupMainFactory.GetInstance<SinacorMain>().Parameter.DataBase.ConnectionInfo.User, EncryptDecrypt.Decrypt(SetupMainFactory.GetInstance<SinacorMain>().Parameter.DataBase.ConnectionInfo.Password), SetupMainFactory.GetInstance<SinacorMain>().Parameter.DataBase.ConnectionInfo.TNSName, SetupMainFactory.GetInstance<SinacorMain>().Parameter.DataBase.ConnectionInfo.IsEncrypted))
            {
                foreach (Configuration.Command command in CompanyCommands.Commands)
                {
                    if (this.IsStopped())
                        break;

                    string stringCommand = null;

                    stringCommand = command.StringCommand.Replace("[COMPANYUSER]", this.Company.Login).Replace("[SYSTEMUSER]", SetupMainFactory.GetInstance<SinacorMain>().Parameter.DataBase.ConnectionInfo.User);

                    string progressDescription = DataBaseGroup.GetProgressDescription(stringCommand);

                    this.IncrementProgress(progressDescription);

                    try
                    {
                        db.ExecuteNonQuery(this.Company.Id, stringCommand);
                    }
                    catch (Exception ex)
                    {
                        this.DecrementProgress(progressDescription);
                        throw new DataBaseException("Erro ao executar o comando", stringCommand, ex);
                    }

                    ExecutedCommandCount++;
                }
            }
        }

        public override void Undo()
        {
            MultipleException multipleException = new MultipleException("Ocorreram erros ao executar os comandos");

            using (OracleDataBase db = new OracleDataBase(SetupMainFactory.GetInstance<SinacorMain>().Parameter.DataBase.ConnectionInfo.User, EncryptDecrypt.Decrypt(SetupMainFactory.GetInstance<SinacorMain>().Parameter.DataBase.ConnectionInfo.Password), SetupMainFactory.GetInstance<SinacorMain>().Parameter.DataBase.ConnectionInfo.TNSName, SetupMainFactory.GetInstance<SinacorMain>().Parameter.DataBase.ConnectionInfo.IsEncrypted))
            {
                for (int i = (ExecutedCommandCount - 1); i >= 0; i--)
                {
                    Configuration.Command command = CompanyCommands.Commands[i];

                    string stringCommand = command.UndoCommand;

                    string progressDescription = DataBaseGroup.GetProgressDescription(stringCommand);

                    this.DecrementProgress(progressDescription);

                    try
                    {
                        if (!String.IsNullOrEmpty(stringCommand))
                            db.ExecuteNonQuery(this.Company.Id, stringCommand);
                    }
                    catch (Exception ex)
                    {
                        multipleException.InnerExceptions.Add(new DataBaseException("Erro ao executar o comando", stringCommand, ex));
                    }
                }
            }

            if (multipleException.InnerExceptions.Count > 0)
                SetupMainFactory.GetInstance<SinacorMain>().WriteStepLog(this, "erros ao tentar desfazer.", multipleException);
        }
    }
}
